package com.cr.dataprotect.config;

import cn.hutool.core.io.IoUtil;
import com.cr.dataprotect.bean.DesensitizationPropertyConfigBean;
import com.cr.dataprotect.bean.ProviderConfigBean;
import com.cr.dataprotect.bean.SensitiveConfigBean;
import com.cr.dataprotect.common.MyConstants;
import com.cr.dataprotect.utils.XmlUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 从配置文件中读取配置。
 *
 * @author ChenRui
 * @date 2023.10.21
 */
@Component
@Slf4j
public class CustomFieldProvider implements FieldProvider {
    /**
     * 字段配置.
     */
    private DataProtectionConfig dataProtectionConfig;


    @PostConstruct
    private void init() {
        try {
            Resource resource = new ClassPathResource("data-protection.xml");
            String content = IoUtil.read(resource.getInputStream(), Charset.defaultCharset());
            dataProtectionConfig = XmlUtil.xmlToEntity(content, DataProtectionConfig.class);
            log.debug("content:{}", content);
        } catch (IOException e) {
            log.warn("未读取到数据保护配置文件", e.getMessage());
        }
    }

    private void initFromPath(String configFilePath) {
        try {
            File file = new File(configFilePath);
            String content = FileUtils.readFileToString(file, Charset.defaultCharset());
            dataProtectionConfig = XmlUtil.xmlToEntity(content, DataProtectionConfig.class);
            log.debug("content:{}", content);
        } catch (IOException e) {
            log.warn("读取数据保护字段配置文件出现异常", e.getMessage());
        }
    }

    /**
     * 配置数据库的敏感字段.
     *
     * @return Map格式，key为数据库，value为字段数组.
     */
    @Override
    public ProviderConfigBean config(String configFilePath) {
        ProviderConfigBean providerConfigBean = new ProviderConfigBean();
        if (StringUtils.isNotEmpty(configFilePath)) {
            initFromPath(configFilePath);
        }
        if (dataProtectionConfig != null) {
            List<DataProtectionConfig.Clazz> clazzList = dataProtectionConfig.getClazzList();
            if (CollectionUtils.isNotEmpty(clazzList)) {
                List<DataProtectionConfig.Clazz> desensitization = new ArrayList<>();
                List<DataProtectionConfig.Clazz> integrity = new ArrayList<>();
                List<DataProtectionConfig.Clazz> sensitive = new ArrayList<>();

                for (DataProtectionConfig.Clazz clazz : clazzList) {
                    if (MyConstants.DESENSITIZATION.equals(clazz.getStrategy())) {
                        desensitization.add(clazz);
                    } else if (MyConstants.INTEGRITY.equals(clazz.getStrategy())) {
                        integrity.add(clazz);
                    } else if (MyConstants.SENSITIVE.equals(clazz.getStrategy())) {
                        sensitive.add(clazz);
                    }
                }
                if (CollectionUtils.isNotEmpty(desensitization)) {
                    providerConfigBean.setDesensitization(loadDesensitizationConfig(desensitization));
                }
                if (CollectionUtils.isNotEmpty(integrity)) {
                    providerConfigBean.setIntegrity(loadIntegrityConfig(integrity));
                }
                if (CollectionUtils.isNotEmpty(sensitive)) {
                    providerConfigBean.setSensitive(loadSensitiveConfig(sensitive));
                }
            }
        } else {
            log.warn("配置加载失败，请检查配置文件");
        }
        return providerConfigBean;
    }

    /**
     * 加载脱敏配置
     *
     * @param clazzList
     */
    private Map<Class, Map<String, Object>> loadDesensitizationConfig(List<DataProtectionConfig.Clazz> clazzList) {
        Map<Class, Map<String, Object>> map = Maps.newHashMap();
        clazzList.forEach(it -> {
            String type = it.getType();
            try {
                Class tableClass = Class.forName(type);
                List<DataProtectionConfig.Property> properties = it.getProperties();
                Map<String, Object> valMap = new HashMap<>();
                if (CollectionUtils.isNotEmpty(properties)) {
                    //转换属性配置
                    List<DesensitizationPropertyConfigBean> propertyConfigBeans = Lists.newArrayList();
                    DesensitizationPropertyConfigBean propertyConfigBean = null;
                    for (DataProtectionConfig.Property prop : properties) {
                        propertyConfigBean = new DesensitizationPropertyConfigBean();
                        propertyConfigBean.setName(prop.getName());
                        List<DataProtectionConfig.ExtProperty> extProperties = prop.getExtProperties();
                        if (CollectionUtils.isNotEmpty(extProperties)) {
                            for (DataProtectionConfig.ExtProperty extProperty : extProperties) {
                                switch (extProperty.getName()) {
                                    case "begin":
                                        propertyConfigBean.setBegin(Integer.valueOf(extProperty.getValue()));
                                        break;
                                    case "end":
                                        propertyConfigBean.setEnd(Integer.valueOf(extProperty.getValue()));
                                        break;
                                    case "value":
                                        propertyConfigBean.setValue(extProperty.getValue().trim().charAt(0));
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                        propertyConfigBeans.add(propertyConfigBean);
                    }

                    valMap.put(MyConstants.PROPERTIES, propertyConfigBeans);
                    map.put(tableClass, valMap);
                }
            } catch (ClassNotFoundException e) {
                log.error("解析脱敏配置出错，找不到该类型：{}", type);
            }
        });

        return map;
    }

    /**
     * 完整性保护配置加载
     *
     * @param clazzList
     * @return
     */
    private Map<Class, Map<String, Object>> loadIntegrityConfig(List<DataProtectionConfig.Clazz> clazzList) {
        Map<Class, Map<String, Object>> map = Maps.newHashMap();
        clazzList.forEach(it -> {
            String type = it.getType();
            List<DataProtectionConfig.ExtClzAttribute> extClzAttributes = it.getExtClzAttributes();
            if (CollectionUtils.isEmpty(extClzAttributes)) {
                log.error("解析完整性配置出错，找不到'extClzAttribute'节点", type);
            }
            String macKeyAlias = "";
            String id = "";
            String t = "";
            String savetable = "";
            for (DataProtectionConfig.ExtClzAttribute extClzAttribute : extClzAttributes) {
                switch (extClzAttribute.getName()) {
                    case "id":
                        id = extClzAttribute.getValue();
                        break;
                    case "table":
                        t = extClzAttribute.getValue();
                        break;
                    case "savetable":
                        savetable = extClzAttribute.getValue();
                        break;
                    default:
                        break;
                }
            }
            if (StringUtils.isNotEmpty(it.getMacKeyAlias())) {
                macKeyAlias = it.getMacKeyAlias();
            }


            try {
                Class tableClass = Class.forName(type);
                List<DataProtectionConfig.Property> properties = it.getProperties();
                Map<String, Object> valMap = new HashMap<>();
                if (CollectionUtils.isNotEmpty(properties)) {
                    valMap.put("macKeyAlias", macKeyAlias);
                    valMap.put("id", id);
                    valMap.put("table", t);
                    valMap.put(MyConstants.PROPERTIES, properties.stream().map(DataProtectionConfig.Property::getName).collect(Collectors.toList())
                            .toArray(new String[properties.size()]));
                    valMap.put("savetable", StringUtils.isNotEmpty(savetable) ? savetable : MyConstants.DEFAULT_SAVE_TABLE);
                    map.put(tableClass, valMap);
                }
            } catch (ClassNotFoundException e) {
                log.error("解析完整性配置出错，找不到该类型：{}", type);
            }

            if (StringUtils.isEmpty(savetable)) {
                log.warn("完整性保护配置中，使用默认完整性数据表");
                //todo 创建表
                //excuteSql();
            }
        });

        return map;
    }

    private void excuteSql() {
        String scriptPath = "integrity_data.sql";
        // 定义数据库连接信息
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String username = "your_username";
        String password = "your_password";

        try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
             Statement statement = connection.createStatement()) {
            // 读取 SQL 脚本内容
            Resource resource = new ClassPathResource(scriptPath);
            String sqlScript = IoUtil.read(resource.getInputStream(), Charset.defaultCharset());
            // 分割 SQL 语句
            String[] sqlStatements = sqlScript.split(";");
            for (String sql : sqlStatements) {
                if (StringUtils.isNotBlank(sql)) {
                    statement.execute(sql.trim());
                }
            }
            log.info("SQL 脚本执行成功");
        } catch (IOException | SQLException e) {
            log.error("执行 SQL 脚本失败", e);
        }
    }

    /**
     * 加载敏感字段配置
     *
     * @param clazzList
     * @return
     */
    private Map<Class, Map<String, Object>> loadSensitiveConfig(List<DataProtectionConfig.Clazz> clazzList) {
        Map<Class, Map<String, Object>> map = Maps.newHashMap();
        clazzList.forEach(clazz -> {
            String type = clazz.getType();
            try {
                Class tableClass = Class.forName(type);
                Map<String, Object> propertiesMap = new HashMap<>();
                List<DataProtectionConfig.Property> properties = clazz.getProperties();
                if (CollectionUtils.isNotEmpty(properties)) {
                    propertiesMap.put("encryptKeyAlias", clazz.getEncryptKeyAlias());
                    List<SensitiveConfigBean> sensitiveConfigBeanList = properties.stream().map(it -> {
                        SensitiveConfigBean sensitiveConfigBean = new SensitiveConfigBean();
                        sensitiveConfigBean.setName(it.getName());
                        return sensitiveConfigBean;
                    }).collect(Collectors.toList());
                    propertiesMap.put(MyConstants.PROPERTIES, sensitiveConfigBeanList);
                    map.put(tableClass, propertiesMap);
                }
            } catch (ClassNotFoundException e) {
                log.error("解析敏感配置出错，找不到该类型：{}", type);
            }
        });

        return map;
    }


}
